package com.longe.controller;

import com.longe.entity.Book;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.SearchResultMapper;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.aggregation.impl.AggregatedPageImpl;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

@RestController
public class SearchController {

    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;

    //实现 基于多字段 分词检索 过滤 排序 分页 高亮
    @RequestMapping("hard/search")
    public List<Book> veryHardSearch() {
        //排序字段
        SortBuilder sortBuilder = new FieldSortBuilder("price").order(SortOrder.DESC);

        //高亮字段
        HighlightBuilder.Field filed = new HighlightBuilder.Field("*")//*表示高亮所有匹配到的属性
                .requireFieldMatch(false) //关闭检索字段匹配
                .preTags("<span style='color:red'>")
                .postTags("</span>");

        SearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withIndices("bookstore") //设置查询索引
                .withTypes("book") //设置查询类型
                .withQuery(QueryBuilders.queryStringQuery("剑玄幻大陆")
                        .field("name").field("content")) //多字段分词检索
                .withFilter(QueryBuilders.rangeQuery("price").gt(100)) //过滤
                .withSort(sortBuilder) //设置排序条件
                .withPageable(PageRequest.of(0, 2))//设置分页参数
                .withHighlightFields(filed) //高亮
                .build();

        AggregatedPage<Book> finalBooks = elasticsearchTemplate.queryForPage(searchQuery, Book.class, new SearchResultMapper() {
            @Override
            public <T> AggregatedPage<T> mapResults(SearchResponse searchResponse, Class<T> aClass, Pageable pageable) {

                List<Book> books = new ArrayList<>();
                //根据searchResponse获取hits
                SearchHits hits = searchResponse.getHits();
                //获取检索结果hits
                SearchHit[] searchHits = hits.getHits();
                //遍历
                for (SearchHit searchHit : searchHits) {
                    Book book = new Book();
                    //获取原始记录
                    Map<String, Object> sourceAsMap = searchHit.getSourceAsMap();
                    //获取高亮map
                    Map<String, HighlightField> highlightFields = searchHit.getHighlightFields();

                    book.setId(sourceAsMap.get("id").toString());
                    book.setName(sourceAsMap.get("name").toString());
                    if (highlightFields.containsKey("name")) {
                        book.setName(highlightFields.get("name").fragments()[0].toString());
                    }
                    book.setContent(sourceAsMap.get("content").toString());
                    if (highlightFields.containsKey("content")) {
                        book.setContent(highlightFields.get("content").fragments()[0].toString());
                    }
                    book.setAuthor(sourceAsMap.get("author").toString());
                    book.setPrice(Double.valueOf(sourceAsMap.get("price").toString()));
                    book.setDateOfPublication(new Date(Long.valueOf(sourceAsMap.get("dateOfPublication").toString())));
                    books.add(book);
                }
                return new AggregatedPageImpl<>((List<T>) books);
            }
        });

        return finalBooks.getContent();
    }
}